package com.tang.officedemo.word.poi;

import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTc;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 生产计划报告模块导出
 * 包含一些简单的字段合并，表格合并操作
 *
 * @author tangfl
 * @since 2024/7/22
 */
@Slf4j
@RestController
public class WorkPlanReportExportProvider {

    /**
     * 原生的POI报表导出
     *
     * @param response res
     * @throws IOException io异常抛出
     */
    @GetMapping("/poi/simple/export")
    public void exportWord(HttpServletResponse response) throws IOException {
        String reportTypeDesc = "本月";
        String descByType = "本月";
        // 创建一个新的Word文档
        XWPFDocument document = new XWPFDocument();
        String formatStart = LocalDateTime.now().toString();
        String formatEnd = LocalDateTime.now().toString();
        String title = "生产作业" + reportTypeDesc + "（" + formatStart + "-" + formatEnd + " ）";
        addParagraphCenter(document, title);
        // 添加段落
        addParagraph(document, "一、电网运行总体情况:");
        addContent(document, "1、电网安全情况：");
        List<String> list = getList();
        if (list.isEmpty()) {
            addContent(document, "");
        } else {
            for (String content : list) {
                addContent(document, content);
            }
        }

        addContent(document, "2、电网运行情况：");
        if (list.isEmpty()) {
            addContent(document, "");
        } else {
            for (String content : list) {
                addContent(document, content);
            }
        }
        addParagraph(document, "二、违章情况");
        addContent(document, "1、本周发生恶性违章" + 1 + "条，严重违章 " +
                1 + " 条，一般违章 " + 1 + " 条。");
        addParagraph(document, "三、作业计划执行情况");
        addContent(document, "1、月作业计划中本周（本月）应完成 " + 1 + " 条，实际完成 " +
                1 + " 条");
        // 添加表格
        List<String> headers = Arrays.asList("序号", "作业计划内容", "时间", "未执行原因");
        // 对象集合 转换为表格识别的 列表类型
        List<List<String>> data = new ArrayList<>();
        int order = 1;
        int temp = 5;
        for (int i = 0; i < temp; i++) {
            WorkPlanStatisticTableVO unExecutePlan = new WorkPlanStatisticTableVO();
            unExecutePlan.setJh("123123");
            unExecutePlan.setYy("123123");
            unExecutePlan.setSj("123123");
            List<String> attributeValues = getAttributeValues(unExecutePlan);
            // 在列表最前面添加序号
            attributeValues.add(0, Integer.toString(order));
            order++;
            data.add(attributeValues);
        }
        addTable(document, headers, data);

        addContent(document, "2、" + descByType + "新增其他作业计划 " + 1 + " 条（月计划中未计划的）");
        // 添加表格
        List<String> headers2 = Arrays.asList("序号", "作业计划内容", "时间");
        List<List<String>> data2 = new ArrayList<>();
        int order2 = 1;
        for (int i = 0; i < temp; i++) {
            WorkPlanStatisticTableVO vo = new WorkPlanStatisticTableVO();
            vo.setJh("12312312");
            vo.setSj("时间");
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, Integer.toString(order2));
            order2++;
            data2.add(attributeValues);
        }
        addTable(document, headers2, data2);


        addParagraph(document, "五、隐患及缺陷消除情况");
        // 添加表格
        List<List<String>> data7 = new ArrayList<>();
        int order7 = 1;
        for (int i = 0; i < temp; i++) {
            DefectHandleStatisticTableVO vo = new DefectHandleStatisticTableVO();
            vo.setA("A");
            vo.setB("A");
            vo.setC("A");
            vo.setD("A");
            vo.setE("A");
            vo.setF("A");
            vo.setG("A");
            vo.setH("A");
            vo.setI("A");
            vo.setJ("A");
            List<String> attributeValues = getAttributeValues(vo);
            attributeValues.add(0, Integer.toString(order7));
            order7++;
            data7.add(attributeValues);
        }
        addMergeTable(document, data7);
        addContent(document, "严重及以上缺陷未消除情况说明:");
        addOverViewTable(document);
        List<String> headers3 = Arrays.asList("序号", "接入单位", "核验表数", "校验规则数", "规范性", "完整性", "准确性", "一致性", "时效性", "总合格率");
        addAnalysisTable(document, headers3, data7);

        response.setContentType("application/vnd.openxmlformats-officedocument.multiprocessing.document;charset=UTF-8");
        //解决跨域不显示在header里面的问题
        response.setHeader("Access-Control-Expose-Headers", "Content-disposition");
        //"attachment"：让浏览器把响应视为附件并下载
        //"inline"：    让浏览器打开Word文档而不是下载它
        response.setHeader("Content-disposition", "attachment; filename=" +
                URLEncoder.encode(title.concat(".docx"), StandardCharsets.UTF_8));
        //BufferedOutputStream缓冲流：可以将数据缓存在内存中，以减少对底层IO的调用次数，从而提高性能。
        //ServletOutputStream：用于向客户端发送数据的
        //因为需要将数据写入HTTP响应，所以使用ServletOutputStream是更好的选择。
        document.write(response.getOutputStream());
        document.close();

    }

    private static List<String> getList() {
        List<String> list = new ArrayList<>();
        list.add("123111111111111");
        list.add("123111111111111");
        list.add("123111111111111");
        list.add("123111111111111");
        return list;
    }

    /**
     * 添加基础文本内容
     */
    private void addContent(XWPFDocument document, String content) {
        document.createParagraph().createRun().setText(content);
    }

    /**
     * 添加段落
     */
    private void addParagraph(XWPFDocument document, String s) {
        XWPFParagraph paragraph1 = document.createParagraph();
        paragraph1.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun run1 = paragraph1.createRun();
        run1.setBold(true);
        run1.setFontSize(16); // 设置标题字体大小
        run1.setText(s);
    }

    /**
     * 添加段落居中
     */
    private void addParagraphCenter(XWPFDocument document, String s) {
        XWPFParagraph paragraph1 = document.createParagraph();
        paragraph1.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun run1 = paragraph1.createRun();
        run1.setBold(true);
        run1.setFontSize(16); // 设置标题字体大小
        run1.setText(s);
    }

    /**
     * 添加动态表格
     */
    private void addTable(XWPFDocument document, List<String> headers, List<List<String>> data) {
        int rowNum = 2;
        if (!Objects.isNull(data) && !data.isEmpty()) {
            rowNum = data.size() + 1;
        }
        // 添加表格
        XWPFTable table = document.createTable(rowNum, headers.size()); // 创建一个3行3列的表格

        // 创建表格后给每个单元格设置样式
        for (int row = 0; row < rowNum; row++) {
            for (int col = 0; col < headers.size(); col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                cell.setWidth("1000");
                addCellCenterStyle(cell);
            }
        }

        // 设置表头
        for (int col = 0; col < headers.size(); col++) {
            XWPFTableCell cell = table.getRow(0).getCell(col);
            cell.setText(headers.get(col));
        }
        // 设置示例数据
        for (int row = 0; row < data.size(); row++) {
            for (int col = 0; col < headers.size(); col++) {
                XWPFTableCell cell = table.getRow(row + 1).getCell(col);
                cell.setText(data.get(row).get(col));
            }
        }
    }

    private void addOverViewTable(XWPFDocument document) {
        int rowNum = 4;
        // 添加表格
        XWPFTable table = document.createTable(rowNum, 7); // 行, 列

        // 创建表格后给每个单元格设置样式
        for (int row = 0; row < rowNum; row++) {
            for (int col = 0; col < 7; col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                cell.setWidth("1200");
                addCellCenterStyle(cell);
            }
        }

        // 合并表格
        mergeCellsVertically(table, 0, 1, 3);
        addTableContext(table, 0, 0, "数据合格率");
        addTableContext(table, 1, 0, "70%");

        mergeCellsHorizontal(table, 0, 1, 2);
        mergeCellsHorizontal(table, 0, 3, 4);
        mergeCellsHorizontal(table, 0, 5, 6);

        addTableContext(table, 0, 1, "质量检测表");
        addTableContext(table, 0, 3, "质量检测规则");
        addTableContext(table, 0, 5, "质量检测数据");

        addTableContext(table, 1, 1, "质量检测表数");
        addTableContext(table, 1, 2, "80");
        addTableContext(table, 2, 1, "问题质量表数");
        addTableContext(table, 2, 2, "80");
        addTableContext(table, 3, 1, "问题质量表占比");
        addTableContext(table, 3, 2, "100%");

        addTableContext(table, 1, 3, "总质量规则数");
        addTableContext(table, 1, 4, "90");
        addTableContext(table, 2, 3, "问题质量规则数");
        addTableContext(table, 2, 4, "100");
        addTableContext(table, 3, 3, "问题质量规则占比");
        addTableContext(table, 3, 4, "90%");

        addTableContext(table, 1, 5, "检测数据量");
        addTableContext(table, 1, 6, "80");
        addTableContext(table, 2, 5, "问题数据量");
        addTableContext(table, 2, 6, "100");
        addTableContext(table, 3, 5, "问题数据比率");
        addTableContext(table, 3, 6, "80%");


    }

    /**
     * 添加动态表格
     */
    private void addMergeTable(XWPFDocument document, List<List<String>> data) {
        int rowNum = 4;
        if (!Objects.isNull(data) && !data.isEmpty()) {
            rowNum = data.size() + 3;
        }
        // 添加表格
        XWPFTable table = document.createTable(rowNum, 10);

        // 创建表格后给每个单元格设置样式
        for (int row = 0; row < rowNum; row++) {
            for (int col = 0; col < 10; col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                cell.setWidth("1000");
                addCellCenterStyle(cell);
            }
        }

        mergeCellsHorizontal(table, 0, 1, 6);
        mergeCellsHorizontal(table, 0, 7, 9);
        mergeCellsHorizontal(table, 1, 1, 2);
        mergeCellsHorizontal(table, 1, 3, 4);
        mergeCellsHorizontal(table, 1, 5, 6);

        mergeCellsVertically(table, 0, 0, 2);
        mergeCellsVertically(table, 7, 1, 2);
        mergeCellsVertically(table, 8, 1, 2);
        mergeCellsVertically(table, 9, 1, 2);
        //手动设置表头
        addTableContext(table, 0, 0, "项目部");
        addTableContext(table, 0, 1, "本周发现及处理情况");
        addTableContext(table, 0, 7, "累计未消除缺陷");

        addTableContext(table, 1, 1, "危急缺陷");
        addTableContext(table, 1, 3, "重大缺陷");
        addTableContext(table, 1, 5, "一般缺陷");

        addTableContext(table, 1, 7, "危急缺陷");
        addTableContext(table, 1, 8, "重大缺陷");
        addTableContext(table, 1, 9, "一般缺陷");

        addTableContext(table, 2, 1, "发现");
        addTableContext(table, 2, 2, "消除");
        addTableContext(table, 2, 3, "发现");
        addTableContext(table, 2, 4, "消除");
        addTableContext(table, 2, 5, "发现");
        addTableContext(table, 2, 6, "消除");

        // 设置示例数据
        for (int row = 0; row < data.size(); row++) {
            for (int col = 0; col < 10; col++) {
                XWPFTableCell cell = table.getRow(row + 3).getCell(col);
                cell.setText(data.get(row).get(col));
            }
        }
    }

    private static void addTableContext(XWPFTable table, int row, int col, String text) {
        XWPFTableCell cell = table.getRow(row).getCell(col);
        cell.setText(text);
    }

    /**
     * 添加水平居中样式
     */
    private void addCellCenterStyle(XWPFTableCell cell) {
        CTTc ctTc = cell.getCTTc();
        //获取 CTP
        CTP ctP = (ctTc.sizeOfPArray() == 0) ?
                ctTc.addNewP() : ctTc.getPArray(0);
        //获取段落
        XWPFParagraph par = cell.getParagraph(ctP);
        //设置水平居中
        par.setAlignment(ParagraphAlignment.CENTER);
        // 垂直居中
        cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);

    }

    /**
     * 跨列合并
     * table要合并单元格的表格
     * row要合并哪一行的单元格
     * fromCell开始合并的单元格
     * toCell合并到哪一个单元格
     */
    public static void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {
        for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {
            XWPFTableCell cell = table.getRow(row).getCell(cellIndex);
            if (cellIndex == fromCell) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * 跨行合并
     * table要合并单元格的表格
     * col要合并哪一列的单元格
     * fromRow从哪一行开始合并单元格
     * toRow合并到哪一个行
     */
    public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
        for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
            XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
            if (rowIndex == fromRow) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            }
        }
    }

    /**
     * 获取对象属性值并转换成字符串列表
     */
    public static List<String> getAttributeValues(Object obj) {
        Class<?> objClass = obj.getClass();
        List<String> valuesList = new ArrayList<>();
        // 获取对象定义的所有属性
        Field[] fields = objClass.getDeclaredFields();
        // 遍历属性并获取属性值
        for (Field field : fields) {
            field.setAccessible(true); // 设置私有属性可访问
            try {
                Object value = field.get(obj);
                String valueStr = (value != null) ? value.toString() : "";
                valuesList.add(valueStr);
            } catch (IllegalAccessException e) {
                log.error("{0}", e);
            }
        }
        return valuesList;
    }


    private void addAnalysisTable(XWPFDocument document, List<String> headers, List<List<String>> data) {
        int rowNum = 2;
        if (!Objects.isNull(data) && !data.isEmpty()) {
            rowNum = data.size() + 2;
        }
        // 添加表格
        XWPFTable table = document.createTable(rowNum, headers.size()); // 创建一个3行3列的表格

        // 创建表格后给每个单元格设置样式
        for (int row = 0; row < rowNum; row++) {
            for (int col = 0; col < headers.size(); col++) {
                XWPFTableCell cell = table.getRow(row).getCell(col);
                cell.setWidth("1000");
                addCellCenterStyle(cell);
            }
        }

        // 设置表头
        for (int col = 0; col < headers.size(); col++) {
            int pos = 1;
            if (col < 4) {
                pos = 0;
            }
            XWPFTableCell cell = table.getRow(pos).getCell(col);
            cell.setText(headers.get(col));
        }
        // 设置示例数据
        for (int row = 0; row < data.size(); row++) {
            for (int col = 0; col < headers.size(); col++) {
                XWPFTableCell cell = table.getRow(row + 2).getCell(col);
                cell.setText(data.get(row).get(col));
            }
        }
        // 合并表头
        for (int i = 0; i < 4; i++) {
            mergeCellsVertically(table, i, 0, 1);
        }
        mergeCellsHorizontal(table, 0, 4, 9);
        addTableContext(table, 0, 4, "评估维度（合格率）");

    }

}